#include "DataSet.h"

// Contrói um conjunto de dados vazio
DataSet::DataSet(int nInVars, int nOutVars)
{
    this->nInVars = nInVars;
    this->nOutVars = nOutVars;
    deleteAll = false;
    time = 0;
}

// Carrega o conjunto de entradas/saídas de um arquivo
DataSet::DataSet(const char *file, int filetype)
{
    deleteAll = true;

    CSVFile f(file, CSV_IN);

    this->filetype = filetype;

    vdouble vd(2);
    f.read(vd);
    nInVars = vd.getuint(0);
    nOutVars = vd.getuint(1);

    // Caso seja um arquivo de saída, carrega-se também a taxa de sucesso e o tempo
    if(filetype == OUTPUT)
    {
        vd.resize(1);
        f.read(vd);
        successRate = vd.get(0);

        vd.resize(1);
        f.read(vd);
        time = vd.get(0);
    }

    while(f.has())
    {
        if(filetype == INPUT)
            vd.resize(nInVars + nOutVars);
        else
            vd.resize(nInVars + 2 * nOutVars);
        f.read(vd);
        Data *io = new Data(nInVars, nOutVars, vd, filetype);
        data.push_back(io);
    }

    print();
}

DataSet::~DataSet()
{
    if(deleteAll)
        for(uint i = 0; i < data.size(); i++)
            delete data[i];
}

// Retorna a entrada/saída de índice i
Data *DataSet::get(uint i)
{
    return data[i];
}

// Retorna o número de entradas/saídas
uint DataSet::size()
{
    return data.size();
}

// Retorna o número de variáveis de entrada
uint DataSet::getNumberOfInVars()
{
    return nInVars;
}

// Retorna o número de variáveis de saída
uint DataSet::getNumberOfOutVars()
{
    return nOutVars;
}

//Adiciona uma data a estrutura
void DataSet::addData(Data *d)
{
    data.push_back(d);
}

// Calcula a taxa de sucesso
void DataSet::calculateSuccessRate()
{
    uint count = 0;

    for(uint i = 0; i < data.size(); i++)
        if(data[i]->hasSucceeded())
            count++;

    successRate = count / (double) data.size();
}

// Retorna a taxa de sucesso
double DataSet::getSuccessRate()
{
    return successRate;
}

// Seta a taxa de sucesso
void DataSet::setSuccessRate(double rate)
{
    successRate = rate;
}

// Retorna o tempo de treinamento ou de teste
double DataSet::getTime()
{
    return time;
}

// Seta o tempo de treinamento ou de teste
void DataSet::setTime(double time)
{
    this->time = time;
}

// Salva as entradas/saídas em um arquivo
void DataSet::saveToFile(const char *file)
{
    CSVFile f(file, CSV_OUT);

    f.write(nInVars);
    f.write(nOutVars);
    f.wendl();

    f.write(successRate);
    f.wendl();
    f.write(time);
    f.wendl();

    for(uint i = 0; i < data.size(); i++)
    {
        f.write(data[i]->getInputVector());
        f.write(data[i]->getOutputVector());
        f.write(data[i]->getNeuralOutputVector());
        f.wendl();
    }
}

// Imprime informações na tela
void DataSet::print()
{
    cout << "#=| INPUT/OUTPUT SET |=================================#" << endl << endl;

    cout << "Number of input variables: " << nInVars << endl;
    cout << "Number of output variables: " << nOutVars << endl;

    if(filetype == OUTPUT)
    {
        cout << "Success Rate: " << successRate << endl;
        cout << "Total training/test time: " << time << " ms" << endl;
    }
    cout << endl;

    for(uint i = 0; i < data.size(); i++)
    {
        cout << "Input/Ouput " << (i + 1) << endl;

        cout << " |--> Input:  ";
        data[i]->printInput();
        cout << endl;

        cout << " |--> Output: ";
        data[i]->printOutput();
        cout << endl;

        if(filetype == OUTPUT)
        {
            cout << " |--> Neural Output: ";
            data[i]->printNeuralOutput();
            cout << endl;
        }
    }

    cout << endl << "#======================================================#" << endl << endl;
}

